/*
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <libfdt.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_platform.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/fdt/fdt_domain.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/timer/fdt_timer.h>
#include <sbi_utils/ipi/fdt_ipi.h>
#include <sbi_utils/reset/fdt_reset.h>


#define AP_HART_COUNT		1

struct sbi_platform platform;

static int aurora_early_init(bool cold_boot)
{
	if (cold_boot) {
		// do some early init such as pinmux initialization or clock init
	}
	return 0;
}

static void aurora_modify_dt(void *fdt)
{
	fdt_cpu_fixup(fdt);
	fdt_fixups(fdt);
	fdt_domain_fixup(fdt);
}

static int aurora_final_init(bool cold_boot)
{
	void *fdt;
	if (!cold_boot)
		return 0;

	fdt = sbi_scratch_thishart_arg1_ptr();
	aurora_modify_dt(fdt);
	return 0;
}


static int aurora_domains_init(void)
{
	return fdt_domains_populate(sbi_scratch_thishart_arg1_ptr());
}

static u32 hart_index2id[AP_HART_COUNT] = {0};

unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
				unsigned long arg2, unsigned long arg3,
				unsigned long arg4)
{
	const char *model;
	void *fdt = (void *)arg1;
	u32 hartid, hart_count = 0;
	int rc, root_offset, cpus_offset, cpu_offset, len;

	root_offset = fdt_path_offset(fdt, "/");
	if (root_offset < 0)
		goto fail;

	model = fdt_getprop(fdt, root_offset, "model", &len);
	if (model)
		sbi_strncpy(platform.name, model, sizeof(platform.name) - 1);

	cpus_offset = fdt_path_offset(fdt, "/cpus");
	if (cpus_offset < 0)
		goto fail;

	fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
		rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
		if (rc)
			continue;

		if (SBI_HARTMASK_MAX_BITS <= hartid)
			continue;

		if (!fdt_node_is_enabled(fdt, cpu_offset))
			continue;

		hart_index2id[hart_count++] = hartid;
	}

	platform.hart_count = hart_count;


	/* Return original FDT pointer */
	return arg1;

fail:
	while (1)
		wfi();
}

const struct sbi_platform_operations platform_ops = {
	.early_init         = aurora_early_init,
	.final_init         = aurora_final_init,
	.domains_init       = aurora_domains_init,
	.console_init       = fdt_serial_init,
	.irqchip_init       = fdt_irqchip_init,
	.irqchip_exit       = fdt_irqchip_exit,
	.ipi_init           = fdt_ipi_init,
	.ipi_exit           = fdt_ipi_exit,
	.timer_init         = fdt_timer_init,
	.timer_exit         = fdt_timer_exit,
};



struct sbi_platform platform = {
	.opensbi_version    = OPENSBI_VERSION,
	.platform_version   = SBI_PLATFORM_VERSION(0x0U, 0x01U),
	.name               = "aurora",
	.features           = SBI_PLATFORM_DEFAULT_FEATURES,
	.hart_count         = AP_HART_COUNT,
	.hart_index2id      = hart_index2id,
	.hart_stack_size    = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
	.platform_ops_addr  = (unsigned long)&platform_ops
};

